/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.misc;


import java.util.Map;
import java.util.WeakHashMap;


/**
 * A new field for augmented object.
 *
 * @param <Family>  the "family" of the field
 * @param <Value>   the type of the new field's values
 */
final public class Augment<Family, Value> {

	
	/**
	 * Maps a family type to the number of extensions for that family.
	 */
	private static Map<Class, Integer> extensions = new WeakHashMap<Class,Integer>();
	
	
	/**
	 * The index of this augment.  Used for random-access lookup in
	 * Augmented instance's list of augments.
	 */
	final int index;
	
	
	
	/**
	 * Constructs a new augment.
	 * 
	 * @param index  the index of the augment 
	 */
	private Augment(int index) {
		this.index = index;
	}

	
	/**
	 * Creates a new augment field.
	 * 
	 * @param <F>  the augmented family type  
	 * @param <V>  the type of the new field's values
	 * @param family  the augmented family type
	 * @param value   the type of the new field's values
	 * @return   the augment field
	 * @throws   IllegalStateException  if the family class inherits from a previously augmented class
	 */
	synchronized public static <F extends Augmented,V> 
	Augment<F,V> create(Class<F> family, Class<V> value) {
		if (!family.getSuperclass().equals(Augmented.class)) {
			throw new IllegalArgumentException(family.getName() + " is not a direct subclass of Augmented");
		}
		Integer count = extensions.get(family);
		if (count == null) {
			count = 0;
		} else {
			count++;
		}
		extensions.put(family, count);
		return new Augment<F,V>(count);
	}
	
	
	/**
	 * Returns the number of extensions for the given family.
	 * 
	 * @param <F>     the type of the family
	 * @param family  the type of the family
	 * @return        the number of extensions for that family
	 */
	synchronized static <F extends Augmented> int getExtensionCount(Class<F> family) {
		Integer r = extensions.get(family);
		if (r == null) {
			return 0;
		} else {
			return r;
		}
	}
	
}
